﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using JXT.PrimaryKey.Batman.Collections;
using JXT.PrimaryKey.Batman.Domain.Services;
using JXT.PrimaryKey.Batman.Domain.Specifications;
using JXT.PrimaryKey.Batman.Domain.VirtualExchange.Models;
using JXT.PrimaryKey.Batman.Domain.VirtualExchange.Repositories;
using JXT.PrimaryKey.Batman.Domain.Quotation.Models;
using JXT.PrimaryKey.Batman.Domain.Repositories;

namespace JXT.PrimaryKey.Batman.Domain.VirtualExchange.Services.Default
{
    public class UserTransactionDetailService : CachedServiceBase<UserTransactionDetail>, IUserTransactionDetailService
    {
        private static readonly int _defaultWaitTime = 20; //wait 20ms

        #region IUserTransactionDetailService Members

        public void Add(UserTransactionDetail entity)
        {
            if (entity == null)
                throw new ArgumentNullException("entity");
            //if (entity.Id > 0)
            //    throw new ArgumentException("entity.Id must be 0.");
            LoadRepository<IUserTransactionDetailRepository>().Add(entity);
        }

        public void Add(IEnumerable<UserTransactionDetail> source, Action<TaskExecutedStatus> updateAction = null)
        {
            if (source == null)
                throw new ArgumentNullException("source");
            int total = source.Count();
            int finished = 0;
            int skip = 0;
            double rate = 0;
            RepositoryContext.BeginTransaction();
            try
            {
                foreach (var item in source)
                {
                    LoadRepository<IUserTransactionDetailRepository>().Add(item);
                    UpdateProcess(total, ref finished, ref skip, ref rate, false, updateAction);
                    Thread.Sleep(_defaultWaitTime);
                }
                RepositoryContext.CommitTransaction();
            }
            catch
            {
                RepositoryContext.RollbackTransaction();
                throw;
            }
            finally
            {
                RepositoryContext.DisposeTransaction();
            }
        }

        public void Delete(UserTransactionDetail entity)
        {
            if (entity == null)
                throw new ArgumentNullException("entity");
            if (entity.Id <= 0)
                throw new ArgumentNullException("entity.Id must be larger than 0.");
            LoadRepository<ISecuritiesDetailRepository>().Delete(entity.Id);
        }

        public int Count(ISpecification<UserTransactionDetail> specification)
        {
            if (specification == null)
                throw new ArgumentNullException("specification");
            return LoadRepository<IUserTransactionDetailRepository>().Count(specification);
        }
        
        public UserTransactionDetail GetSingle(int id)
        {
            var specification = SpecificationFactory.CreateSpecification<UserTransactionDetail>();
            specification.And(e => e.Id == id);
            return GetSingle(specification);
        }

        public UserTransactionDetail GetSingle(ISpecification<UserTransactionDetail> specification)
        {
            if (specification == null)
                throw new ArgumentNullException("specification");
            var find = LoadRepository<IUserTransactionDetailRepository>().GetSingle(specification);
            return find;
        }

        public IPagedCollection<UserTransactionDetail> GetList(IPagedSpecification<UserTransactionDetail> specification)
        {
            if (specification == null)
                throw new ArgumentNullException("specification");
            var list = LoadRepository<IUserTransactionDetailRepository>().GetList(specification);
            return list;
        }

        public IEnumerable<UserTransactionDetail> GetListByProfit(int pageSize, int pageIndex, int typeId, RankCountType rankCountType = RankCountType.Unknown)
        {
            if (pageSize <= 0)
                pageSize = 10;
            if (pageIndex <= 0)
                pageIndex = 1;
            DateTime? lastDateTime = LoadRepository<IUserTransactionDetailRepository>().GetLastDateTime(rankCountType);
            IEnumerable<UserTransactionDetail> list = new List<UserTransactionDetail>();
            if (null == lastDateTime)
                return list;
            var pagedSpecification = SpecificationFactory.CreatePagedSpecification<UserTransactionDetail>();
            pagedSpecification.IsEnablePaged = true;
            pagedSpecification.PageSize = pageSize;
            pagedSpecification.PageIndex = pageIndex;
            pagedSpecification.And(e => e.TypeId == typeId);
            if (rankCountType == RankCountType.Unknown)//总收益排行,从日数据里面查找
            {
                pagedSpecification.And(e => e.UpdateTime == lastDateTime.Value && e.CountType == RankCountType.Day);
                pagedSpecification.OrderBy(e => e.HKTotalProfit, Specifications.OrderType.Descending);
            }
            else
            {
                pagedSpecification.And(e => e.CountType == rankCountType && e.UpdateTime == lastDateTime.Value);
                pagedSpecification.OrderBy(e => e.HKCycleProfit, Specifications.OrderType.Descending);
            }

            list = LoadRepository<IUserTransactionDetailRepository>().GetList(pagedSpecification);
            return list;
        }

        public int GetCountByProfit(int typeId, RankCountType rankCountType = RankCountType.Unknown)
        {
            DateTime? lastDateTime = LoadRepository<IUserTransactionDetailRepository>().GetLastDateTime(rankCountType);
            IEnumerable<UserTransactionDetail> list = new List<UserTransactionDetail>();
            if (null == lastDateTime)
                return 0;
            var pagedSpecification = SpecificationFactory.CreatePagedSpecification<UserTransactionDetail>();
            pagedSpecification.And(e => e.TypeId == typeId);
            if (rankCountType == RankCountType.Unknown)//总收益排行,从日数据里面查找
            {
                pagedSpecification.And(e => e.UpdateTime == lastDateTime.Value && e.CountType == RankCountType.Day);
            }
            else
            {
                pagedSpecification.And(e=> e.UpdateTime == lastDateTime.Value && e.CountType == rankCountType);
            }
            list = LoadRepository<IUserTransactionDetailRepository>().GetList(pagedSpecification);
            return list.Count();
            
        }

        public IEnumerable<UserTransactionDetail> GetListByTurnover(int pageSize, int pageIndex, int typeId)
        {
            if (pageSize <= 0)
                pageSize = 10;
            if (pageIndex <= 0)
                pageIndex = 1;
            DateTime? lastDateTime = LoadRepository<IUserTransactionDetailRepository>().GetLastDateTime(RankCountType.Day);
            IEnumerable<UserTransactionDetail> list = new List<UserTransactionDetail>();
            if (null == lastDateTime)
                return list;
            var pagedSpecification = SpecificationFactory.CreatePagedSpecification<UserTransactionDetail>();
            pagedSpecification.IsEnablePaged = true;
            pagedSpecification.PageSize = pageSize;
            pagedSpecification.PageIndex = pageIndex;
            pagedSpecification.And(e => e.TypeId == typeId && e.UpdateTime == lastDateTime.Value && e.CountType == RankCountType.Day);
            pagedSpecification.OrderBy(e => e.HKTotalTurnover, Specifications.OrderType.Descending);
            list = LoadRepository<IUserTransactionDetailRepository>().GetList(pagedSpecification);
            return list;
        }

        public TransactionDetailSequence GetLastDateTranscationInfo(int userId, int typeId)
        {
            DateTime? lastDateTime = LoadRepository<IUserTransactionDetailRepository>().GetLastDateTime(RankCountType.Day);
            DateTime? lastWeekDateTime = LoadRepository<IUserTransactionDetailRepository>().GetLastDateTime(RankCountType.Week);
            TransactionDetailSequence detailSequence = new TransactionDetailSequence();
            if (null == lastDateTime)
                return null;
            if (null == lastWeekDateTime)
            {
                detailSequence.WeekEarningsRate = 0;
                detailSequence.WeekEarningsRateSequence = 0;
            }
            else
            {
                var pagedSpecificationWeek = SpecificationFactory.CreatePagedSpecification<UserTransactionDetail>();
                pagedSpecificationWeek.And(e => e.UserId == userId && e.TypeId == typeId && e.UpdateTime == lastWeekDateTime.Value.Date && e.CountType == RankCountType.Week);
                var resultWeek = LoadRepository<IUserTransactionDetailRepository>().GetSingleByUserId(pagedSpecificationWeek);
                if (resultWeek != null)
                {
                    detailSequence.WeekEarningsRate = resultWeek.HKCycleEarningsRate;
                    detailSequence.WeekEarningsRateSequence = resultWeek.HKCycleEarningsRateSequence;
                }
            }
            var pagedSpecification = SpecificationFactory.CreatePagedSpecification<UserTransactionDetail>();
            pagedSpecification.And(e => e.UserId == userId && e.TypeId == typeId && e.UpdateTime == lastDateTime.Value.Date && e.CountType == RankCountType.Day);
            var result = LoadRepository<IUserTransactionDetailRepository>().GetSingleByUserId(pagedSpecification);
            if (result != null)
            {
                detailSequence.TotalEarningsRate = result.HKTotalEarningsRate;
                detailSequence.TotalEarningsRateSequence = result.HKTotalEarningsRateSequence;
                detailSequence.DayEarningsRate = result.HKCycleEarningsRate;
                detailSequence.DayEarningsRateSequence = result.HKCycleEarningsRateSequence;
                detailSequence.TradTurnover = result.HKTotalTurnover;
            }
            return detailSequence;
        }

        public IEnumerable<UserTransactionDetail> GetList(int userId, int typeId, DateTime startTime, DateTime endTime)
        {
            if (startTime > endTime)
                throw new ArgumentException("endtime can not lt starttime");
            var pagedSpecification = SpecificationFactory.CreatePagedSpecification<UserTransactionDetail>();
            pagedSpecification.And(e => e.UserId == userId && e.TypeId == typeId && e.CountType == RankCountType.Day && e.UpdateTime >= startTime.Date && e.UpdateTime <= endTime.Date);
            var result = LoadRepository<IUserTransactionDetailRepository>().GetList(pagedSpecification);
            return result;
        }

        public UserTransactionDetail GetLastSingle(int userId, int typeId, DateTime time, RankCountType type)
        {
            return LoadRepository<IUserTransactionDetailRepository>().GetLastSingle(userId, typeId, time, type);
        }

        public UserTransactionDetail GetCurrentOrLastSingle(int userId, int typeId, DateTime time, RankCountType type)
        {
            return LoadRepository<IUserTransactionDetailRepository>().GetCurrentOrLastSingle(userId, typeId, time, type);
        }

        #endregion

        private void UpdateProcess(int total, ref int finished, ref int skip, ref double rate, bool isSkip, Action<TaskExecutedStatus> updateAction)
        {
            finished++;
            if (isSkip)
                skip++;
            double newRate = (double)finished / (double)total * 100;
            if ((newRate - rate >= 0.5 || finished == total) && updateAction != null)
            {
                try
                {
                    updateAction(new TaskExecutedStatus() { Finished = finished, Total = total, Skip = skip });
                }
                catch { }
                rate = newRate;
            }
        }

        #region override method
        public override RepositoryContext RepositoryContext
        {
            get
            {
                return LoadRepository<IUserTransactionDetailRepository>().Context;
            }
        }
        #endregion
    }
}
